# coding=utf-8

from typing import Tuple, Optional
import json

from app.cores.dictionaries import TEST_FIELD, MATCHING_RULE, EXPECTATION_LOGIC
from app.cores.assertion import AssertEqual, AssertSubString, AssertContains, AssertMatches, AssertXPath


def get_expectations_result(expectations, request, expectation_logic) -> bool:
    """
    获取期望结果
    :param expectations: 当前请求案例中所有期望/断言数据, 如果没有设置期望则应该是一个空list。会在执行后将结果更新到表中。
    :param request: 请求和应答信息 <class HTTPRequest>
    :param expectation_logic: 期望逻辑处理 与-断言全部是True时则返回True；否-断言只要有一个是True时返回True
    :return: 只要有一个断言失败则返回False，全部成功则返回True
    """
    rets = []
    if expectations:
        for expectation in expectations:
            actual_value = _get_actual_value_from_test_field(test_field=expectation.test_field, request=request)
            last_result, last_failure_msg = _assert(
                expected=expectation.value_,
                actual=actual_value,
                matching_rule=expectation.matching_rule,
                negater=expectation.negater,
            )
            rets.append(last_result)
            # 解决HTTP响应文本内容包含html片段导致前台解析问题 begin
            if last_result is False and expectation.test_field == TEST_FIELD.TEXT_RESPONSE:
                last_failure_msg = '[期望值: %s] [实际值: 请参考“响应-响应体”中内容]' % expectation.value_
            # 解决HTTP响应文本内容包含html片段导致前台解析问题 end
            expectation.update_assert_result(last_result=last_result, last_failure_msg=last_failure_msg)
    if len(rets) == 0:  # 未设置期望断言则结果为True
        return True
    if expectation_logic == EXPECTATION_LOGIC.AND:
        return all(rets)
    if expectation_logic == EXPECTATION_LOGIC.OR:
        return any(rets)


def _get_actual_value_from_test_field(test_field, request):
    """
    根据测试字段获取请求应答中的实际值
    :param test_field: 测试字段
    :param request: 请求应答信息 <class HTTPRequest>
    :return:
    """
    if test_field == TEST_FIELD.TEXT_RESPONSE:
        if isinstance(request.response_body, str):  # request.response_body可能是个字符串或字典
            return request.response_body
        elif isinstance(request.response_body, dict):
            return json.dumps(request.response_body, ensure_ascii=False, default=str)
    if test_field == TEST_FIELD.RESPONSE_HEADERS:
        return json.dumps(request.response_headers, ensure_ascii=False)
    if test_field == TEST_FIELD.REQUEST_DATA:
        return json.dumps(request.request_body, ensure_ascii=False)
    if test_field == TEST_FIELD.REQUEST_HEADERS:
        return json.dumps(request.request_headers, ensure_ascii=False)
    if test_field == TEST_FIELD.RESPONSE_CODE:
        return request.response_status_code


def _assert(expected, actual, matching_rule, negater) -> Tuple[bool, Optional[str]]:
    """
    根据matching_rule匹配模式类型进行断言
    :param expected: 期望值
    :param actual: 实际值
    :param matching_rule: 匹配模式
    :param negater: 是否取反
    :return:
    """
    if matching_rule == MATCHING_RULE.EQUALS:
        return AssertEqual(expected=expected, actual=actual, negater=negater).exec()
    if matching_rule == MATCHING_RULE.SUBSTRING:
        return AssertSubString(expected=expected, actual=actual, negater=negater).exec()
    if matching_rule == MATCHING_RULE.CONTAINS:
        return AssertContains(expected=expected, actual=actual, negater=negater).exec()
    if matching_rule == MATCHING_RULE.MATCHES:
        return AssertMatches(expected=expected, actual=actual, negater=negater).exec()
    if matching_rule == MATCHING_RULE.XPATH:
        return AssertXPath(expected=expected, actual=actual, negater=negater).exec()
    raise ValueError('暂不支持 %s 匹配模式' % matching_rule)

